import { PickerAssembly, convertMatrix } from '@amcax/renderer';
import { AssemblyPreview } from '@app-cad-env/product/types/preview-types';
import { ctx2 } from '@app-cad/module';
import { refDocNodes } from '@app-cad/pages/product-support/assembly-funcs';
import {
  generateProductPickObj,
  PickedProduct,
} from '@app-cad/common/components/pick-input/pick-product';

export class AssemblyNodePreview {
  private readonly previewNodesMap = new Map<string, PickedProduct>();

  constructor(private readonly picker: PickerAssembly) {}

  private finishPreview(
    dxid: string,
    picked: PickedProduct,
    restoreOriginalNode: boolean,
  ) {
    ctx2.cadScene.assisGroup.remove(picked);
    picked.destroy?.();

    if (restoreOriginalNode) {
      this.picker.setFirstLevelChildVisibility(dxid, true);
    }
  }

  preview(asmPreviews: AssemblyPreview[] = []) {
    for (const { dxid, matrix } of asmPreviews) {
      if (this.previewNodesMap.has(dxid)) {
        const picked = this.previewNodesMap.get(dxid);
        if (picked && matrix) {
          // 如果已经存在预览节点，则更新其矩阵
          picked.applyMatrix4(picked.matrix.clone().invert());
          picked.applyMatrix4(convertMatrix(matrix));
        }
      } else {
        // 如果不存在预览节点，则创建新的预览节点
        const refNode = refDocNodes.get(dxid);
        if (refNode?.recursivelyVisible) {
          this.picker.setFirstLevelChildVisibility(dxid, false);

          const pickObj = generateProductPickObj(
            refNode,
            null,
            true,
          ).assisObj.cloneSelf();
          if (matrix) {
            pickObj.applyMatrix4(convertMatrix(matrix));
          }
          ctx2.cadScene.assisGroup.add(pickObj);
          this.previewNodesMap.set(dxid, pickObj);
        }
      }
    }

    const previewIds = new Set(asmPreviews.map(({ dxid }) => dxid));
    for (const [dxid, picked] of this.previewNodesMap.entries()) {
      if (!previewIds.has(dxid)) {
        // 如果传入的预览列表中不包含该dxid，则移除预览节点
        this.finishPreview(dxid, picked, true);

        this.previewNodesMap.delete(dxid);
      }
    }
    ctx2.viewer.requestRender();
  }

  destroy(restoreOriginalNode: boolean) {
    for (const [dxid, picked] of this.previewNodesMap.entries()) {
      this.finishPreview(dxid, picked, restoreOriginalNode);
    }

    this.previewNodesMap.clear();
    ctx2.viewer.requestRender();
  }
}
